Skip to content

Integration branch for ably-pubsub-server v4 package - #693

Open
ttypic wants to merge 31 commits into
mainfrom
integration/v4
Open

ttypic wants to merge 31 commits into
mainfrom
integration/v4

Conversation

@ttypic

@ttypic ttypic commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Integration branch contains packages split, renaming and deletion of deprecated methods

@coderabbitai

coderabbitai Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 304 files, which is 204 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

Usage-priced reviews support at most 300 files.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: af227af6-9c80-4fdd-9d10-33f051c11ce9
📥 Commits

Reviewing files that changed from the base of the PR and between d6429f4 and 7032b4c.

⛔ Files ignored due to path filters: 1
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing: 304
  • .claude/skills/release/SKILL.md
  • .claude/skills/uts-to-python/SKILL.md
  • .github/workflows/release.yml
  • .gitignore
  • CONTRIBUTING.md
  • LONG_DESCRIPTION.rst
  • README.md
  • UPDATING.md
  • ably/__init__.py
  • ably/pubsub/http/__init__.py
  • ably/pubsub/http/annotations.py
  • ably/pubsub/http/auth.py
  • ably/pubsub/http/channel.py
  • ably/pubsub/http/http.py
  • ably/pubsub/http/push.py
  • ably/pubsub/liveobjects/__init__.py
  • ably/pubsub/liveobjects/batch.py
  • ably/pubsub/liveobjects/defaults.py
  • ably/pubsub/liveobjects/enums.py
  • ably/pubsub/liveobjects/instance.py
  • ably/pubsub/liveobjects/livecounter.py
  • ably/pubsub/liveobjects/livemap.py
  • ably/pubsub/liveobjects/liveobject.py
  • ably/pubsub/liveobjects/objectid.py
  • ably/pubsub/liveobjects/objectmessage.py
  • ably/pubsub/liveobjects/objectspool.py
  • ably/pubsub/liveobjects/pathobject.py
  • ably/pubsub/liveobjects/pathobjectsubscriptionregister.py
  • ably/pubsub/liveobjects/publicmessage.py
  • ably/pubsub/liveobjects/realtimeobject.py
  • ably/pubsub/liveobjects/subscription.py
  • ably/pubsub/liveobjects/syncobjectspool.py
  • ably/pubsub/liveobjects/valuetypes.py
  • ably/pubsub/prototypes.py
  • ably/pubsub/realtime/__init__.py
  • ably/pubsub/realtime/annotations.py
  • ably/pubsub/realtime/channel.py
  • ably/pubsub/realtime/connection.py
  • ably/pubsub/realtime/connectionmanager.py
  • ably/pubsub/realtime/presence.py
  • ably/pubsub/realtime/presencemap.py
  • ably/pubsub/realtime/realtime.py
  • ably/pubsub/request/__init__.py
  • ably/pubsub/request/http.py
  • ably/pubsub/request/httputils.py
  • ably/pubsub/request/paginatedresult.py
  • ably/pubsub/scripts/__init__.py
  • ably/pubsub/scripts/unasync.py
  • ably/pubsub/server/__init__.py
  • ably/pubsub/server/liveobjects.py
  • ably/pubsub/server/sync.py
  • ably/pubsub/transport/__init__.py
  • ably/pubsub/transport/defaults.py
  • ably/pubsub/transport/websockettransport.py
  • ably/pubsub/types/__init__.py
  • ably/pubsub/types/annotation.py
  • ably/pubsub/types/authoptions.py
  • ably/pubsub/types/batch.py
  • ably/pubsub/types/capability.py
  • ably/pubsub/types/channeldetails.py
  • ably/pubsub/types/channelmode.py
  • ably/pubsub/types/channeloptions.py
  • ably/pubsub/types/channelstate.py
  • ably/pubsub/types/channelsubscription.py
  • ably/pubsub/types/connectiondetails.py
  • ably/pubsub/types/connectionerrors.py
  • ably/pubsub/types/connectionstate.py
  • ably/pubsub/types/device.py
  • ably/pubsub/types/flags.py
  • ably/pubsub/types/message.py
  • ably/pubsub/types/mixins.py
  • ably/pubsub/types/operations.py
  • ably/pubsub/types/options.py
  • ably/pubsub/types/presence.py
  • ably/pubsub/types/stats.py
  • ably/pubsub/types/testoptions.py
  • ably/pubsub/types/tokendetails.py
  • ably/pubsub/types/tokenrequest.py
  • ably/pubsub/types/typedbuffer.py
  • ably/pubsub/util/__init__.py
  • ably/pubsub/util/case.py
  • ably/pubsub/util/clock.py
  • ably/pubsub/util/construction.py
  • ably/pubsub/util/crypto.py
  • ably/pubsub/util/encoding.py
  • ably/pubsub/util/eventemitter.py
  • ably/pubsub/util/exceptions.py
  • ably/pubsub/util/helper.py
  • ably/pubsub/util/nocrypto.py
  • ably/pubsub/vcdiff/__init__.py
  • ably/pubsub/vcdiff/defaultvcdiffdecoder.py
  • ably/pubsub/version.py
  • pyproject.toml
  • test/ably/http/authheaders_test.py
  • test/ably/http/encoders_test.py
  • test/ably/http/httpannotations_test.py
  • test/ably/http/httpauth_test.py
  • test/ably/http/httpbatch_test.py
  • test/ably/http/httpcapability_test.py
  • test/ably/http/httpchannelhistory_test.py
  • test/ably/http/httpchannelmutablemessages_test.py
  • test/ably/http/httpchannelpublish_test.py
  • test/ably/http/httpchannels_test.py
  • test/ably/http/httpchannelstatus_test.py
  • test/ably/http/httpcrypto_test.py
  • test/ably/http/httphttp_test.py
  • test/ably/http/httpinit_test.py
  • test/ably/http/httppaginatedresult_test.py
  • test/ably/http/httppresence_test.py
  • test/ably/http/httppush_test.py
  • test/ably/http/httprequest_test.py
  • test/ably/http/httpstats_test.py
  • test/ably/http/httptime_test.py
  • test/ably/http/httptoken_test.py
  • test/ably/realtime/deltadecoding_test.py
  • test/ably/realtime/eventemitter_test.py
  • test/ably/realtime/presencemap_test.py
  • test/ably/realtime/realtimeannotations_test.py
  • test/ably/realtime/realtimeauth_test.py
  • test/ably/realtime/realtimechannel_publish_test.py
  • test/ably/realtime/realtimechannel_test.py
  • test/ably/realtime/realtimechannel_vcdiff_test.py
  • test/ably/realtime/realtimechannelmutablemessages_test.py
  • test/ably/realtime/realtimeconnection_test.py
  • test/ably/realtime/realtimeinit_test.py
  • test/ably/realtime/realtimepresence_test.py
  • test/ably/realtime/realtimeresume_test.py
  • test/ably/testapp.py
  • test/ably/utils.py
  • test/unit/annotation_test.py
  • test/unit/batch_test.py
  • test/unit/clock_test.py
  • test/unit/http_test.py
  • test/unit/liveobjects/__init__.py
  • test/unit/liveobjects/batch_test.py
  • test/unit/liveobjects/conftest.py
  • test/unit/liveobjects/realtime_object_test.py
  • test/unit/liveobjects/subscription_test.py
  • test/unit/liveobjects/typed_views_test.py
  • test/unit/liveobjects/value_types_test.py
  • test/unit/message_test.py
  • test/unit/mutable_message_test.py
  • test/unit/options_test.py
  • test/unit/pubsub_server_test.py
  • test/unit/websockettransport_test.py
  • test/uts/README.md
  • test/uts/deviations.md
  • test/uts/helpers/client.py
  • test/uts/helpers/clock.py
  • test/uts/helpers/mock_http_test.py
  • test/uts/helpers/mock_websocket.py
  • test/uts/helpers/mock_websocket_test.py
  • test/uts/helpers/presence.py
  • test/uts/helpers/sandbox.py
  • test/uts/objects/__init__.py
  • test/uts/objects/helpers/__init__.py
  • test/uts/objects/helpers/standard_test_pool.py
  • test/uts/objects/helpers/standard_test_pool_test.py
  • test/uts/objects/integration/__init__.py
  • test/uts/objects/integration/conftest.py
  • test/uts/objects/integration/objects_gc_test.py
  • test/uts/objects/integration/objects_lifecycle_test.py
  • test/uts/objects/integration/objects_sync_test.py
  • test/uts/objects/integration/proxy/__init__.py
  • test/uts/objects/integration/proxy/conftest.py
  • test/uts/objects/integration/proxy/objects_faults_test.py
  • test/uts/objects/unit/__init__.py
  • test/uts/objects/unit/instance_test.py
  • test/uts/objects/unit/internal_live_counter_api_test.py
  • test/uts/objects/unit/internal_live_counter_test.py
  • test/uts/objects/unit/internal_live_map_api_test.py
  • test/uts/objects/unit/internal_live_map_test.py
  • test/uts/objects/unit/live_object_subscribe_test.py
  • test/uts/objects/unit/object_id_test.py
  • test/uts/objects/unit/objects_pool_test.py
  • test/uts/objects/unit/parent_references_test.py
  • test/uts/objects/unit/path_object_mutations_test.py
  • test/uts/objects/unit/path_object_subscribe_test.py
  • test/uts/objects/unit/path_object_test.py
  • test/uts/objects/unit/public_object_message_test.py
  • test/uts/objects/unit/realtime_object_test.py
  • test/uts/objects/unit/value_types_test.py
  • test/uts/realtime/integration/auth/token_renewal_test.py
  • test/uts/realtime/integration/auth/token_request_test.py
  • test/uts/realtime/integration/auth_test.py
  • test/uts/realtime/integration/channel_history_test.py
  • test/uts/realtime/integration/channels/channel_attach_test.py
  • test/uts/realtime/integration/channels/channel_publish_test.py
  • test/uts/realtime/integration/channels/channel_subscribe_test.py
  • test/uts/realtime/integration/connection/connection_failures_test.py
  • test/uts/realtime/integration/connection_lifecycle_test.py
  • test/uts/realtime/integration/delta_decoding_test.py
  • test/uts/realtime/integration/mutable_messages_test.py
  • test/uts/realtime/integration/presence/presence_sync_test.py
  • test/uts/realtime/integration/presence_lifecycle_test.py
  • test/uts/realtime/integration/proxy/auth_reauth_test.py
  • test/uts/realtime/integration/proxy/channel_faults_test.py
  • test/uts/realtime/integration/proxy/connection_open_failures_test.py
  • test/uts/realtime/integration/proxy/connection_resume_test.py
  • test/uts/realtime/integration/proxy/heartbeat_test.py
  • test/uts/realtime/integration/proxy/presence_reentry_test.py
  • test/uts/realtime/integration/proxy/rest_faults_test.py
  • test/uts/realtime/unit/auth/auth_callback_errors_test.py
  • test/uts/realtime/unit/auth/connection_auth_test.py
  • test/uts/realtime/unit/auth/realtime_authorize_test.py
  • test/uts/realtime/unit/auth/token_expiry_non_renewable_test.py
  • test/uts/realtime/unit/channels/channel_additional_attached_test.py
  • test/uts/realtime/unit/channels/channel_annotations_test.py
  • test/uts/realtime/unit/channels/channel_attach_test.py
  • test/uts/realtime/unit/channels/channel_attributes_test.py
  • test/uts/realtime/unit/channels/channel_connection_state_test.py
  • test/uts/realtime/unit/channels/channel_delta_decoding_test.py
  • test/uts/realtime/unit/channels/channel_detach_test.py
  • test/uts/realtime/unit/channels/channel_error_test.py
  • test/uts/realtime/unit/channels/channel_get_message_test.py
  • test/uts/realtime/unit/channels/channel_history_test.py
  • test/uts/realtime/unit/channels/channel_message_versions_test.py
  • test/uts/realtime/unit/channels/channel_options_test.py
  • test/uts/realtime/unit/channels/channel_properties_test.py
  • test/uts/realtime/unit/channels/channel_publish_pending_test.py
  • test/uts/realtime/unit/channels/channel_publish_test.py
  • test/uts/realtime/unit/channels/channel_server_initiated_detach_test.py
  • test/uts/realtime/unit/channels/channel_state_events_test.py
  • test/uts/realtime/unit/channels/channel_subscribe_test.py
  • test/uts/realtime/unit/channels/channel_update_delete_message_test.py
  • test/uts/realtime/unit/channels/channel_when_state_test.py
  • test/uts/realtime/unit/channels/channels_collection_test.py
  • test/uts/realtime/unit/channels/message_field_population_test.py
  • test/uts/realtime/unit/client/realtime_client_test.py
  • test/uts/realtime/unit/client/realtime_request_test.py
  • test/uts/realtime/unit/client/realtime_stats_test.py
  • test/uts/realtime/unit/client/realtime_time_test.py
  • test/uts/realtime/unit/client/realtime_timeouts_test.py
  • test/uts/realtime/unit/connection/auto_connect_test.py
  • test/uts/realtime/unit/connection/backoff_jitter_test.py
  • test/uts/realtime/unit/connection/connection_failures_test.py
  • test/uts/realtime/unit/connection/connection_id_key_test.py
  • test/uts/realtime/unit/connection/connection_open_failures_test.py
  • test/uts/realtime/unit/connection/connection_ping_test.py
  • test/uts/realtime/unit/connection/connection_recovery_test.py
  • test/uts/realtime/unit/connection/error_reason_test.py
  • test/uts/realtime/unit/connection/fallback_hosts_test.py
  • test/uts/realtime/unit/connection/forwards_compatibility_test.py
  • test/uts/realtime/unit/connection/heartbeat_test.py
  • test/uts/realtime/unit/connection/server_initiated_reauth_test.py
  • test/uts/realtime/unit/connection/update_events_test.py
  • test/uts/realtime/unit/connection/when_state_test.py
  • test/uts/realtime/unit/presence/local_presence_map_test.py
  • test/uts/realtime/unit/presence/presence_map_test.py
  • test/uts/realtime/unit/presence/presence_sync_test.py
  • test/uts/realtime/unit/presence/realtime_presence_channel_state_test.py
  • test/uts/realtime/unit/presence/realtime_presence_enter_test.py
  • test/uts/realtime/unit/presence/realtime_presence_get_test.py
  • test/uts/realtime/unit/presence/realtime_presence_history_test.py
  • test/uts/realtime/unit/presence/realtime_presence_reentry_test.py
  • test/uts/realtime/unit/presence/realtime_presence_subscribe_test.py
  • test/uts/rest/integration/auth_test.py
  • test/uts/rest/integration/batch_presence_test.py
  • test/uts/rest/integration/mutable_messages_test.py
  • test/uts/rest/integration/pagination_test.py
  • test/uts/rest/integration/presence_test.py
  • test/uts/rest/integration/proxy/rest_fallback_test.py
  • test/uts/rest/integration/publish_test.py
  • test/uts/rest/integration/push_admin_test.py
  • test/uts/rest/integration/push_channels_test.py
  • test/uts/rest/integration/revoke_tokens_test.py
  • test/uts/rest/integration/time_stats_test.py
  • test/uts/rest/unit/auth/auth_callback_test.py
  • test/uts/rest/unit/auth/auth_scheme_test.py
  • test/uts/rest/unit/auth/authorize_test.py
  • test/uts/rest/unit/auth/client_id_test.py
  • test/uts/rest/unit/auth/revoke_tokens_test.py
  • test/uts/rest/unit/auth/token_details_test.py
  • test/uts/rest/unit/auth/token_renewal_test.py
  • test/uts/rest/unit/batch_presence_test.py
  • test/uts/rest/unit/batch_publish_test.py
  • test/uts/rest/unit/channel/annotations_test.py
  • test/uts/rest/unit/channel/get_message_test.py
  • test/uts/rest/unit/channel/history_test.py
  • test/uts/rest/unit/channel/idempotency_test.py
  • test/uts/rest/unit/channel/message_versions_test.py
  • test/uts/rest/unit/channel/publish_result_test.py
  • test/uts/rest/unit/channel/publish_test.py
  • test/uts/rest/unit/channel/rest_channel_attributes_test.py
  • test/uts/rest/unit/channel/update_delete_message_test.py
  • test/uts/rest/unit/channels_collection_test.py
  • test/uts/rest/unit/encoding/message_encoding_test.py
  • test/uts/rest/unit/encoding/msgpack_interop_test.py
  • test/uts/rest/unit/fallback_test.py
  • test/uts/rest/unit/presence/rest_presence_test.py
  • test/uts/rest/unit/push/push_admin_publish_test.py
  • test/uts/rest/unit/push/push_channel_subscriptions_test.py
  • test/uts/rest/unit/push/push_channels_test.py
  • test/uts/rest/unit/push/push_device_registrations_test.py
  • test/uts/rest/unit/rest_client_test.py
  • test/uts/rest/unit/stats_test.py
  • test/uts/rest/unit/time_test.py
  • test/uts/rest/unit/types/error_types_test.py
  • test/uts/rest/unit/types/message_types_test.py
  • test/uts/rest/unit/types/mutable_message_types_test.py
  • test/uts/rest/unit/types/options_types_test.py
  • test/uts/rest/unit/types/paginated_result_test.py
  • test/uts/rest/unit/types/presence_message_types_test.py
  • test/uts/rest/unit/types/token_types_test.py

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

One or more issues must be addressed before approval.

Review effort: Lite
Findings: 1 High severity · 4 Medium severity

Open (5)
What changed in this PR

Splits the SDK into the ably-pubsub-server distribution and updates public imports, factories, synchronous generation, documentation, and tests.

Changes:

  • Migrates modules and tests to ably.pubsub.
  • Adds factory/prototype-based client construction.
  • Updates packaging, documentation, and release configuration.
File Description
UPDATING.md Updated as part of this pull request.
test/​uts/​rest/​unit/​types/​token_types_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​types/​presence_message_types_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​types/​paginated_result_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​types/​options_types_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​types/​mutable_message_types_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​types/​message_types_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​types/​error_types_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​time_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​stats_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​rest_client_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​push/​push_device_registrations_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​push/​push_channels_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​push/​push_channel_subscriptions_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​push/​push_admin_publish_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​presence/​rest_presence_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​fallback_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​encoding/​msgpack_interop_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​encoding/​message_encoding_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​channels_collection_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​channel/​update_delete_message_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​channel/​rest_channel_attributes_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​channel/​publish_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​channel/​publish_result_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​channel/​message_versions_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​channel/​idempotency_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​channel/​history_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​channel/​get_message_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​channel/​annotations_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​batch_publish_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​batch_presence_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​auth/​token_renewal_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​auth/​token_details_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​auth/​revoke_tokens_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​auth/​client_id_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​auth/​authorize_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​auth/​auth_scheme_test.py Updated as part of this pull request.
test/​uts/​rest/​unit/​auth/​auth_callback_test.py Updated as part of this pull request.
test/​uts/​rest/​integration/​time_stats_test.py Updated as part of this pull request.
test/​uts/​rest/​integration/​revoke_tokens_test.py Updated as part of this pull request.
test/​uts/​rest/​integration/​push_channels_test.py Updated as part of this pull request.
test/​uts/​rest/​integration/​push_admin_test.py Updated as part of this pull request.
test/​uts/​rest/​integration/​publish_test.py Updated as part of this pull request.
test/​uts/​rest/​integration/​proxy/​rest_fallback_test.py Updated as part of this pull request.
test/​uts/​rest/​integration/​presence_test.py Updated as part of this pull request.
test/​uts/​rest/​integration/​pagination_test.py Updated as part of this pull request.
test/​uts/​rest/​integration/​mutable_messages_test.py Updated as part of this pull request.
test/​uts/​rest/​integration/​batch_presence_test.py Updated as part of this pull request.
test/​uts/​rest/​integration/​auth_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​presence/​realtime_presence_subscribe_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​presence/​realtime_presence_reentry_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​presence/​realtime_presence_history_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​presence/​realtime_presence_get_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​presence/​realtime_presence_enter_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​presence/​realtime_presence_channel_state_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​presence/​presence_sync_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​presence/​presence_map_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​presence/​local_presence_map_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​connection/​when_state_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​connection/​update_events_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​connection/​server_initiated_reauth_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​connection/​heartbeat_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​connection/​forwards_compatibility_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​connection/​fallback_hosts_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​connection/​error_reason_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​connection/​connection_recovery_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​connection/​connection_ping_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​connection/​connection_open_failures_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​connection/​connection_id_key_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​connection/​connection_failures_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​connection/​backoff_jitter_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​connection/​auto_connect_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​client/​realtime_timeouts_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​client/​realtime_time_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​client/​realtime_stats_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​client/​realtime_request_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​client/​realtime_client_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​message_field_population_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channels_collection_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_when_state_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_update_delete_message_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_subscribe_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_state_events_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_server_initiated_detach_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_publish_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_publish_pending_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_properties_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_options_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_message_versions_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_history_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_get_message_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_error_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_detach_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_delta_decoding_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_connection_state_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_attributes_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_attach_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_annotations_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​channels/​channel_additional_attached_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​auth/​token_expiry_non_renewable_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​auth/​realtime_authorize_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​auth/​connection_auth_test.py Updated as part of this pull request.
test/​uts/​realtime/​unit/​auth/​auth_callback_errors_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​proxy/​rest_faults_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​proxy/​presence_reentry_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​proxy/​heartbeat_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​proxy/​connection_resume_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​proxy/​connection_open_failures_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​proxy/​channel_faults_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​proxy/​auth_reauth_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​presence/​presence_sync_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​presence_lifecycle_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​mutable_messages_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​delta_decoding_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​connection/​connection_failures_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​connection_lifecycle_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​channels/​channel_subscribe_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​channels/​channel_publish_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​channels/​channel_attach_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​channel_history_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​auth/​token_request_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​auth/​token_renewal_test.py Updated as part of this pull request.
test/​uts/​realtime/​integration/​auth_test.py Updated as part of this pull request.
test/​uts/​README.md Updated as part of this pull request.
test/​uts/​helpers/​sandbox.py Updated as part of this pull request.
test/​uts/​helpers/​presence.py Updated as part of this pull request.
test/​uts/​helpers/​mock_websocket.py Updated as part of this pull request.
test/​uts/​helpers/​mock_websocket_test.py Updated as part of this pull request.
test/​uts/​helpers/​mock_http_test.py Updated as part of this pull request.
test/​uts/​helpers/​clock.py Updated as part of this pull request.
test/​uts/​helpers/​client.py Updated as part of this pull request.
test/​unit/​websockettransport_test.py Updated as part of this pull request.
test/​unit/​pubsub_server_test.py Updated as part of this pull request.
test/​unit/​options_test.py Updated as part of this pull request.
test/​unit/​mutable_message_test.py Updated as part of this pull request.
test/​unit/​message_test.py Updated as part of this pull request.
test/​unit/​http_test.py Updated as part of this pull request.
test/​unit/​clock_test.py Updated as part of this pull request.
test/​unit/​annotation_test.py Updated as part of this pull request.
test/​ably/​utils.py Updated as part of this pull request.
test/​ably/​testapp.py Updated as part of this pull request.
test/​ably/​realtime/​realtimeresume_test.py Updated as part of this pull request.
test/​ably/​realtime/​realtimepresence_test.py Updated as part of this pull request.
test/​ably/​realtime/​realtimeinit_test.py Updated as part of this pull request.
test/​ably/​realtime/​realtimeconnection_test.py Updated as part of this pull request.
test/​ably/​realtime/​realtimechannelmutablemessages_test.py Updated as part of this pull request.
test/​ably/​realtime/​realtimechannel_vcdiff_test.py Updated as part of this pull request.
test/​ably/​realtime/​realtimechannel_test.py Updated as part of this pull request.
test/​ably/​realtime/​realtimechannel_publish_test.py Updated as part of this pull request.
test/​ably/​realtime/​realtimeauth_test.py Updated as part of this pull request.
test/​ably/​realtime/​realtimeannotations_test.py Updated as part of this pull request.
test/​ably/​realtime/​presencemap_test.py Updated as part of this pull request.
test/​ably/​realtime/​eventemitter_test.py Updated as part of this pull request.
test/​ably/​realtime/​deltadecoding_test.py Updated as part of this pull request.
test/​ably/​http/​httptoken_test.py Updated as part of this pull request.
test/​ably/​http/​httptime_test.py Updated as part of this pull request.
test/​ably/​http/​httpstats_test.py Updated as part of this pull request.
test/​ably/​http/​httprequest_test.py Updated as part of this pull request.
test/​ably/​http/​httppush_test.py Updated as part of this pull request.
test/​ably/​http/​httppresence_test.py Updated as part of this pull request.
test/​ably/​http/​httppaginatedresult_test.py Updated as part of this pull request.
test/​ably/​http/​httphttp_test.py Updated as part of this pull request.
test/​ably/​http/​httpcrypto_test.py Updated as part of this pull request.
test/​ably/​http/​httpchannelstatus_test.py Updated as part of this pull request.
test/​ably/​http/​httpchannels_test.py Updated as part of this pull request.
test/​ably/​http/​httpchannelpublish_test.py Updated as part of this pull request.
test/​ably/​http/​httpchannelmutablemessages_test.py Updated as part of this pull request.
test/​ably/​http/​httpchannelhistory_test.py Updated as part of this pull request.
test/​ably/​http/​httpcapability_test.py Updated as part of this pull request.
test/​ably/​http/​httpannotations_test.py Updated as part of this pull request.
test/​ably/​http/​encoders_test.py Updated as part of this pull request.
README.md Updated as part of this pull request.
pyproject.toml Updated as part of this pull request.
LONG_DESCRIPTION.rst Updated as part of this pull request.
CONTRIBUTING.md Updated as part of this pull request.
ably/​vcdiff/​__init__.py Updated as part of this pull request.
ably/​pubsub/​version.py Updated as part of this pull request.
ably/​pubsub/​vcdiff/​defaultvcdiffdecoder.py Updated as part of this pull request.
ably/​pubsub/​vcdiff/​__init__.py Updated as part of this pull request.
ably/​pubsub/​util/​nocrypto.py Updated as part of this pull request.
ably/​pubsub/​util/​helper.py Updated as part of this pull request.
ably/​pubsub/​util/​exceptions.py Updated as part of this pull request.
ably/​pubsub/​util/​eventemitter.py Updated as part of this pull request.
ably/​pubsub/​util/​encoding.py Updated as part of this pull request.
ably/​pubsub/​util/​crypto.py Updated as part of this pull request.
ably/​pubsub/​util/​construction.py Updated as part of this pull request.
ably/​pubsub/​util/​clock.py Updated as part of this pull request.
ably/​pubsub/​util/​case.py Updated as part of this pull request.
ably/​pubsub/​util/​__init__.py Updated as part of this pull request.
ably/​pubsub/​types/​typedbuffer.py Updated as part of this pull request.
ably/​pubsub/​types/​tokenrequest.py Updated as part of this pull request.
ably/​pubsub/​types/​tokendetails.py Updated as part of this pull request.
ably/​pubsub/​types/​testoptions.py Updated as part of this pull request.
ably/​pubsub/​types/​stats.py Updated as part of this pull request.
ably/​pubsub/​types/​presence.py Updated as part of this pull request.
ably/​pubsub/​types/​options.py Updated as part of this pull request.
ably/​pubsub/​types/​operations.py Updated as part of this pull request.
ably/​pubsub/​types/​mixins.py Updated as part of this pull request.
ably/​pubsub/​types/​message.py Updated as part of this pull request.
ably/​pubsub/​types/​flags.py Updated as part of this pull request.
ably/​pubsub/​types/​device.py Updated as part of this pull request.
ably/​pubsub/​types/​connectionstate.py Updated as part of this pull request.
ably/​pubsub/​types/​connectionerrors.py Updated as part of this pull request.
ably/​pubsub/​types/​connectiondetails.py Updated as part of this pull request.
ably/​pubsub/​types/​channelsubscription.py Updated as part of this pull request.
ably/​pubsub/​types/​channelstate.py Updated as part of this pull request.
ably/​pubsub/​types/​channeloptions.py Updated as part of this pull request.
ably/​pubsub/​types/​channelmode.py Updated as part of this pull request.
ably/​pubsub/​types/​channeldetails.py Updated as part of this pull request.
ably/​pubsub/​types/​capability.py Updated as part of this pull request.
ably/​pubsub/​types/​authoptions.py Updated as part of this pull request.
ably/​pubsub/​types/​annotation.py Updated as part of this pull request.
ably/​pubsub/​types/​__init__.py Updated as part of this pull request.
ably/​pubsub/​transport/​websockettransport.py Updated as part of this pull request.
ably/​pubsub/​transport/​defaults.py Updated as part of this pull request.
ably/​pubsub/​transport/​__init__.py Updated as part of this pull request.
ably/​pubsub/​server/​sync.py Updated as part of this pull request.
ably/​pubsub/​scripts/​unasync.py Updated as part of this pull request.
ably/​pubsub/​scripts/​__init__.py Updated as part of this pull request.
ably/​pubsub/​request/​paginatedresult.py Updated as part of this pull request.
ably/​pubsub/​request/​httputils.py Updated as part of this pull request.
ably/​pubsub/​request/​http.py Updated as part of this pull request.
ably/​pubsub/​request/​__init__.py Updated as part of this pull request.
ably/​pubsub/​realtime/​realtime.py Updated as part of this pull request.
ably/​pubsub/​realtime/​presencemap.py Updated as part of this pull request.
ably/​pubsub/​realtime/​presence.py Updated as part of this pull request.
ably/​pubsub/​realtime/​connectionmanager.py Updated as part of this pull request.
ably/​pubsub/​realtime/​connection.py Updated as part of this pull request.
ably/​pubsub/​realtime/​channel.py Updated as part of this pull request.
ably/​pubsub/​realtime/​annotations.py Updated as part of this pull request.
ably/​pubsub/​realtime/​__init__.py Updated as part of this pull request.
ably/​pubsub/​prototypes.py Updated as part of this pull request.
ably/​pubsub/​http/​push.py Updated as part of this pull request.
ably/​pubsub/​http/​http.py Updated as part of this pull request.
ably/​pubsub/​http/​channel.py Updated as part of this pull request.
ably/​pubsub/​http/​auth.py Updated as part of this pull request.
ably/​pubsub/​http/​annotations.py Updated as part of this pull request.
ably/​pubsub/​http/​__init__.py Updated as part of this pull request.
ably/​__init__.py Updated as part of this pull request.
.gitignore Updated as part of this pull request.
.github/​workflows/​release.yml Updated as part of this pull request.
.claude/​skills/​uts-to-python/​SKILL.md Updated as part of this pull request.
.claude/​skills/​release/​SKILL.md Updated as part of this pull request.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

name: python-package-distributions
path: dist/
- name: Check that wheel and tarball contains ably/sync/
- name: Check that wheel and tarball contains ably/pubsub/sync/
Comment thread README.md Outdated
Comment thread UPDATING.md
Comment thread ably/pubsub/version.py
"""

api_version = '5'
lib_version = '3.1.4'
Comment thread pyproject.toml
@@ -1,9 +1,9 @@
[project]
name = "ably"
name = "ably-pubsub-server"
ttypic and others added 8 commits October 8, 2026 15:37
Publish the SDK as `ably-pubsub-server` rather than `ably`, installing into
`ably/pubsub` so that further per-product distributions can share the `ably`
namespace. All existing code moves to `ably/pubsub` unchanged; the public API
is now reached through `ably.pubsub.server`.

Neither `ably` nor `ably.pubsub` carries an `__init__.py` — both are PEP 420
namespace packages. This matters for the next distribution: a regular package
wins outright over any namespace portion during import resolution, so an
`ably/pubsub/__init__.py` here would silently shadow an `ably/pubsub/client`
installed under a different sys.path entry, which is exactly what an editable
checkout of this repo alongside a released sibling looks like.

Consequences of having no package root to put things in:

- `api_version` and `lib_version` move to `ably/pubsub/version.py`, as
  `http/httputils.py` and `types/options.py` read them and core code must not
  depend on the server package.
- The NullHandler silencing the library's loggers moves to
  `ably/pubsub/util/__init__.py`, the one module every entry point imports.
- unasync writes the sync tree to `ably/pubsub/sync` and maps
  `ably.pubsub.server` onto the hand-written `ably.pubsub.server.sync`.

Also fix `HttpUtils.default_headers()`, which read `api_version` and
`lib_version` off the `ably` namespace and so raised AttributeError. Only the
integration tests cover the Ably-Agent header, so the unit suite was silent
on it.

Tests import from `ably.pubsub.server`; UPDATING.md covers the 4.0.0 migration.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Expose create_http_client() and create_realtime_client() as the only way to build
a client, so that the package a client comes from names the side the application
runs on. AblyRest and AblyRealtime are no longer exported from ably.pubsub.server
and raise TypeError when constructed directly, naming the factory to reach for
instead; a ContextVar opened by the factories is what separates a permitted
construction from a direct one.

Callers who annotated against the client classes should use the prototypes the
factories return. ably/pubsub/prototypes.py declares RestClient and RealtimeClient
as typing.Protocol definitions of the client surface, which the concrete classes
satisfy structurally. They are called prototypes because "protocol" already means
the Ably wire protocol here.

- typing.Protocol makes 3.8 the minimum supported Python, which the CI matrix and
  README already assumed. requires-python and the classifiers now say so, which in
  turn retires two dead sys.version_info blocks in the tests.
- Expand the factory docstrings to cover every client option, grouped by concern
  and derived from Options and AuthOptions rather than copied from the
  constructors.
- Drop `keep_alive` from the AblyRest docstring. It has been documented since the
  constructor was written, but no option of that name exists and passing it raises
  TypeError.

test/unit/pubsub_server_test.py covers the factories, the guard — including that
permission does not leak past a factory call — the classes being unexported, and
the concrete clients satisfying their prototypes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The distribution was renamed to ably-pubsub-server, so the agent header
should no longer identify the library as ably-python. Report the SDK as
ably-pubsub-python and add a versionless ably-pubsub-server agent entry
so requests are attributable to the server package.

Update the Ably-Agent assertion in the REST HTTP tests to match the new
header format.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…nflicts

- Updated `protocol_members` to handle protocol attribute detection more accurately, relying on `typing._get_protocol_attrs` where available, avoiding unintended attribute inclusion.
- Renamed `ably` test client to `app_setup_client` to prevent shadowing the imported `ably` package and ensure correct resolution during test execution.
- Adjusted `pyproject.toml` to configure `ruff` for consistent lint behavior in both local and CI environments.
The public entry point is create_http_client, but everything behind it was
named "rest": the ably.pubsub.rest package, AblyRest, and the RestClient
prototype. Rename that surface to "http" so the names a caller reads match
the name they call.

The transport package already holding ably.pubsub.http — Http, HttpUtils and
PaginatedResult — moves to ably.pubsub.request to free the name, which also
describes it better: it models individual requests, not the client.

 - ably/pubsub/rest/ -> ably/pubsub/http/, with rest.py -> http.py
 - AblyRest -> AblyHttp, RestAnnotations -> HttpAnnotations,
   RestChannels -> HttpChannels
 - the exported prototypes RestClient and RealtimeClient become
   PubSubHttpClient and PubSubRealtimeClient
 - test/ably/rest/ -> test/ably/http/, rest*_test.py -> http*_test.py,
   TestRest* -> TestHttp*

unasync's rename list, mocked-path replacements and test directories follow
the move, so the generated synchronous flavour lands at ably.pubsub.sync.http.
The spec-defined options rest_host and idempotent_rest_publishing keep their
names, as does "REST" where it refers to the Ably API rather than to a symbol.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Nothing connected AblyHttp and AblyRealtime to the prototypes the factories
return. A hasattr loop in the tests was the only check, and it was weak
enough to call a class with no implemented members conformant.

Have each client name its prototype as a base class, so the relationship is
stated where the client is defined and a type checker verifies it. That alone
would weaken the runtime check, because an unimplemented member then resolves
to the prototype's `...` stub and returns None rather than raising, so the
conformance tests are strengthened to match:

 - the prototype must actually appear in the client's MRO
 - every member must be defined by the client itself, found by dropping the
   prototype's own MRO so an inherited stub cannot satisfy it
 - parameter names, kinds and requiredness must match the prototype, as must
   whether the member is awaitable

The synchronous client is covered too, since unasync generates both sides of
that pair. Annotations are excluded from the signature comparison: the
prototype spells its types as strings under `from __future__ import
annotations` while the clients evaluate theirs, and return types are a type
checker's concern.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The clients now declare their prototype as a base class, so calling them
AblyHttp and AblyRealtime left the two halves of each pair reading as
unrelated types. Name each class after what it is: the default implementation
of its prototype.

 - AblyHttp -> DefaultPubSubHttpClient
 - AblyRealtime -> DefaultPubSubRealtimeClient
 - AblyHttpSync -> DefaultPubSubHttpClientSync, through unasync's rename list

Neither name is exported, and both are reachable only through
create_http_client and create_realtime_client; each class docstring now says
as much.

Tidy the 4.0.0 migration notes in passing. They no longer spell out the
internal rename, which was never part of the public API.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The library now reports itself as `ably-pubsub-python/<version>`, which the
two Ably-Agent tests that came in from main did not expect.

- The mock websocket helper test looked for `ably-python` and now looks for
  the new name.
- `RSC7d/ably-agent-header-format-0` asserts `ably-[a-z]+/<semver>`, which
  rejects a hyphenated library name. RSC7d1 puts no limit on the characters
  of a product key, so the specification is at fault rather than the SDK.
  The test is gated with `@spec_error` and the fault is recorded in
  deviations.md.

`update_message()` takes a `Message`, and the migration guide tells users to
import types like it from `ably.pubsub.server`, but neither server package
exported it. Export it from both.

The README passed the API key positionally to `create_realtime_client`, which
accepts keyword arguments only and so raised TypeError. Pass it as `key=`, and
say in the migration guide that the factories no longer accept a positional
key.

The release job still read the version from `dist/ably-*.tar.gz` and pointed
both environments at `/p/ably`. The sdist is now
`ably_pubsub_server-<version>.tar.gz`, so the tag check would never have
matched it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
owenpearson and others added 9 commits October 8, 2026 17:09
`batch_publish` (RSC22) posts one `BatchPublishSpec`, or a list of
them, to `/messages`, encoding each message per RSL4 and applying
RSL1k1 to each spec separately when idempotent REST publishing is on
(RSC22d). The server answers with an array holding a `BatchResult` per
spec, so a single spec gets the one element back and a list gets the
list. A spec naming no channels or carrying no messages is refused
locally with the 400/40000 the server would answer it with.

`batch_presence` (RSC24) sends the channel names comma-joined in the
`channels` parameter of a GET to `/presence`, and returns the server's
`BatchResult`. The server leaves `presence` out for a channel with no
members, which is read as an empty list.

Both methods are declared on `PubSubHttpClient`, so the realtime and
synchronous clients carry them too. `BatchResult`, `BatchPublishSpec`
and the four per-channel result types (BAR2, BSP2, BPR2, BPF2, BGR2,
BGF2) are exported from `ably.pubsub.server` and
`ably.pubsub.server.sync`. A dict with `channels` and `messages` keys
stands in for a `BatchPublishSpec`, as a dict does for the push admin
types.

The RSL1k1 id assignment moves out of `Channel` into
`assign_idempotent_ids`, which both publish paths share.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The 44 batch Test IDs (47 cases) across `rest/unit` and
`rest/integration` drop their `@deviation` gates and pass. They now
build `BatchPublishSpec` and check result types with `isinstance`, as
the specifications write them.

Every `batch_publish.md` mock answers in the legacy format, a flat
array of per-channel results, which the sandbox sends only to a client
sending `X-Ably-Version: 2` or none. At version 5, which ably-python
sends, `POST /messages` answers every batch, mixed and all-failure ones
included, with 201 and an array holding one `BatchResult` envelope per
spec, a single spec sent as a bare object included. The fixtures are
corrected to that shape through `batch_result()`, and the assertions
stand. Two RSL4c3 assertions compared a stringified JSON payload
byte for byte; they now parse it, as the encoding tests do, since the
specification does not fix the whitespace.

deviations.md drops the batch row from Unimplemented features, and
rewrites the envelope entry: it had concluded that `batch_presence.md`
was the specification to revisit, and the server says it is
`batch_publish.md`. The header and measured counts are re-measured:
172 gated cases, the RSC7d `Ably-Agent` test among them, 1047 passing
derived cases, and 130 helper cases where 122 had been recorded. Three
Smaller faults rows that had been superseded by their filed copies are
removed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The batch publish and token revocation fixtures written in the response
format below protocol version 3 are filed as ably/specification#559.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
4.0 makes ably.pubsub.server the whole public API, but its export list
was carried over from 3.x's top-level ably package, which only
re-exported CipherParams. 3.x users reached generate_random_key and
get_default_params through ably.util.crypto, a submodule that 4.0 moves
and declares internal, so 4.0 left no public way to generate a key
(RSE2) or build default cipher params.

Export both from ably.pubsub.server and ably.pubsub.server.sync, show the
3.x to 4.0 import in UPDATING.md, and make the missing-crypto error name
the ably-pubsub-server[crypto] extra instead of the old ably[crypto].
Export generate_random_key and get_default_params from ably.pubsub.server
feat: add batch publish and batch presence to the HTTP client
Derives the fifteen specifications under uts/objects/unit, 322 tests, and
the shared helper uts/objects/helpers/standard_test_pool.md describes:
the standard pool, its wire builders, the synced-channel setup and the
REST provisioning the integration tier uses.

The pure specifications drive the CRDT objects, the pool and the sync
state machine directly; the rest run against a mock websocket through
channel.object. The public API is reached through the typed views of
LODR-061, so a specification's untyped value(), set() or entries() reads
as as_live_counter().value(), as_live_map().set() and so on.

Where a specification step cannot fail, or reads state before the frame
that changes it has been processed, the test carries the corrected step
under a UTS SPEC ERROR comment and keeps the specification's own
assertions.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Derives the three sandbox specifications under uts/objects/integration
and the proxy specification under uts/objects/integration/proxy, 17
tests. The sandbox ones run under both protocols, against an app of
their own; the proxy ones authenticate with a locally signed JWT, as the
realtime proxy tier does, and fault the objects sync through uts-proxy.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds the ably.pubsub.objects package: the protocol v6 object message
wire types, with their JSON and msgpack encodings; the LWW map and
counter CRDTs with their tombstones, parent references and garbage
collection; the objects pool and the sync sequence that replaces it on
attach, buffering operations until the sync completes; object id
generation; the evaluation of LiveMap and LiveCounter creation values
into create operations; and the public ObjectMessage the subscription
events carry.

A RealtimeObject can be built with no channel, which is how the pure
unit specifications drive the sync state machine. The path-based public
API, publishing and the channel integration follow in later commits and
are stubs here.

Also adds the HAS_OBJECTS flag, the OBJECT_SUBSCRIBE and OBJECT_PUBLISH
channel modes, and the siteCode and objectsGCGracePeriod connection
details.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
owenpearson and others added 14 commits October 19, 2026 10:43
Routes ATTACHED, OBJECT and OBJECT_SYNC to the channel's RealtimeObject,
and every other channel state change to it, so that each attach starts
an objects sync and a detached or failed channel clears its objects.
The transport now hands OBJECT and OBJECT_SYNC frames to the channel at
all.

RealtimeObject.get() attaches the channel through the RTL33
ensure-active-channel procedure and waits for the sync; a write
publishes an OBJECT message and, once its ACK assigns serials, applies
the operations locally rather than waiting for the echo. The internal
counter and map gain their increment, decrement, set and remove, and
the GC sweep runs on the client's clock while the channel is attached.

Connects with protocol version 6, whose wire format the objects
messages use, and identifies to REST as version 6 to match. Adds the
echo_messages client option, sent as the echo connect parameter, which
LiveObjects writes require.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Implements the public API LODR-061 specifies. A PathObject names a
location in the channel's object tree and resolves it on every call, so
it keeps working as the objects at that path are replaced; an Instance
holds one object and follows it wherever it moves. Each has a base
class carrying navigation, instance(), compact() and compact_json(), and
three views, as_live_map(), as_live_counter() and as_primitive(), that
carry the methods specific to a type. The path views are unchecked,
because a path's type can change under it: a read through the wrong
view answers None and a write raises 92005 or 92007. The instance views
check, and raise 92007 at once.

Path subscriptions are dispatched from every object update to each path
the updated object can be reached by, filtered by depth, with the
public ObjectMessage describing the operation.

The LiveObjects public names are exported from ably.pubsub.server.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds the batch API LODR-061 specifies, from the RTBC section of
ably/specification#471: `async with root.batch() as ctx:` resolves the
target once, and the writes made through the context inside the block
are queued and published as a single OBJECT message when the block
exits, so other clients see them as one update. Reads inside the block
resolve against the local tree; a block that raises publishes nothing,
and a context used after its block has closed raises 40000.

batch() is on the map and counter views of both PathObject and
Instance, which is what types the context. LiveMap and LiveCounter
values are evaluated when the batch is published, since creating them
reads the server time.

No UTS specification covers the batch API or the typed views of
LODR-061 yet, so test/unit/objects tests both against their spec points.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds the objects tier to deviations.md: the faults in the uts/objects
specifications the derived tests correct or work around, the shape
adaptations the Python API forces, the claims investigated and refuted
against the sandbox, seven candidate upstream issues, and how the tier
is adopted here. The header counts are re-measured with objects as a
tier of its own, which also corrects the gated count: the RSC7d
spec-error gate was never counted in it.

The UTS README and the uts-to-python skill gain the objects layout, its
helpers, the typed-view translation and the traps met deriving it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
get() and a write waiting for the objects sync now fail with 92008 when
the channel is already detached, failed or released, rather than only
when it moves into one of those states while they wait; before, closing
the client during get()'s attach, or an ERROR arriving with the ACK,
left the wait pending forever. The RTL33 ensure-active-channel step
checks the state the implicit attach ended in, and a write is no longer
applied locally once the channel's objects have been cleared.

An object message that fails to decode, or an operation that raises
while being applied, is logged and skipped on its own, so one bad value
cannot drop the rest of its OBJECT message, or an OBJECT_SYNC's cursor
and so the whole sync. A released channel stops its GC timer, and a
sweep that raises is logged and rescheduled.

Also shares the MAP_SET, MAP_REMOVE and COUNTER_INC construction
between the direct writes and the batch, validates a LiveMap or
LiveCounter value before reading the server time, keeps the GC grace
period from each CONNECTED, and lets typing.get_type_hints resolve the
wire dataclasses.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ably-java and ably-cocoa expose only compactJson, and RTTS3f and RTTS7d
let a typed SDK leave compact out. In Python the two would return dicts
that differ only once the data holds bytes or a shared map, and
json.dumps raises on compact's result at exactly that point. LODR-061
records the choice.

compact_json returns JsonValue, exported with JsonObject from
ably.pubsub.server, and LiveMapInstance and LiveCounterInstance narrow it
per RTTS7a. The UTS compact tests read through compact_json, recorded as
adaptation S-6.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Moves ably.pubsub.objects to ably.pubsub.liveobjects, and its unit tests
to test/unit/liveobjects, following PDR-080: package and import names
carry the product name, while the API keeps the resource name, so
channel.object, RealtimeObject and ObjectMessage are unchanged.

test/uts/objects keeps the specification's directory name, so each
derived test still maps onto the uts/objects specification it comes from.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Moves the thirty LiveObjects names out of ably.pubsub.server into a module
of their own, alongside ably.pubsub.server.sync. Generic names such as
Batch, Subscription, Instance and Primitive no longer share a namespace
with the Pub/Sub ones, where Batch read as part of batch publish next to
BatchResult and BatchPublishSpec, and the product name shows at the
import, as PDR-080 asks:

    from ably.pubsub.server.liveobjects import LiveCounter, LiveMap

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
_decode_number passed any value that was not an int or a float through
unchanged, so a counter increment or count sent as a string decoded and
only failed later, in the counter's arithmetic. It now raises ValueError
for a present value of any other type, so from_protocol_message skips
the ObjectMessage carrying it at decode time.

The RTO9 and RTO5c tests used a string number as their operation that
decodes but fails to apply; they now make the apply raise instead, and a
new RTO8 test covers the string increment as a decode failure.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ched

Specification 6.3.0 replaces RTS4a with RTS4c-e. Channels.release used to
remove a channel whatever its state, so an attached channel was dropped
from the collection while still attached in the Ably service. It now
raises an AblyException with code 90011 and status 400 for a channel that
is not INITIALIZED, DETACHED or FAILED, and leaves the channel as it was
(RTS4e); it still returns quietly for an unknown name (RTS4c) and removes
a channel in one of those states (RTS4d).

This is a breaking change: callers must await channel.detach() before
releasing. 3.x logs a deprecation warning in this case (RTS4b). The
channels collection UTS tests are rederived for RTS4c-e, which closes the
RTS4a release deviation.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
pubsub: raise 90011 when releasing a realtime channel that isn't detached

This branch was successfully deployed

1 active (outdated) deployment
staging/pull/693/features — 4a869cf5 Deployed Oct 8, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

5 participants